package edu.arizona.cs.learn.timeseries.model;

import java.io.File;
import java.io.FileReader;
import java.io.PushbackReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import edu.arizona.cs.learn.timeseries.util.LispReader;


public class Instance {
	private int _id;
	private int _uniqueId;
		
	/** The classification label for this instance */
	private String _label;
	
	private String _stringId;
	
	private List<Interval> _intervals;

	/**
	 * Create a new instance with the given label and id.
	 * @param label -- the supervised classification label.
	 * @param id -- an id
	 */
	public Instance(String label, int id) {
		_label = label;
		_id = id;
	}

	public Instance(String label, int id, List<Interval> intervals) {
		this(label, id);
		_intervals = intervals;
	}
	
	public Instance(String label, String stringId, List<Interval> intervals) { 
		this(label, 1, intervals);
		_stringId = stringId;
	}
	
	public String name() {
		return _label;
	}

	public int id() {
		return _id;
	}

	public int uniqueId() {
		return _uniqueId;
	}

	public void uniqueId(int uniqueId) {
		_uniqueId = uniqueId;
	}
	
	public String stringId() { 
		return _stringId;
	}
	
	public void stringId(String stringId) {
		_stringId = stringId;
	}

	/**
	 * Return the intervals that are part of this
	 * instance.
	 * @return
	 */
	public List<Interval> intervals() { 
		return _intervals;
	}
	
	/**
	 * Set the intervals that make up this instance.
	 * Useful when the original instance is compressed.
	 * @param intervals
	 */
	public void intervals(List<Interval> intervals) { 
		_intervals = intervals;
	}
	

	/**
	 * Return a copy of this Instance
	 * @return
	 */
	public Instance copy() {
		Instance copy = new Instance(_label, _id, _intervals);
		copy.uniqueId(_uniqueId);
		return copy;
	}
	
	/**
	 * Load the file of intervals into an array of instances.
	 * @param file
	 * @return
	 */
	public static List<Instance> load(File file) { 
		String name = file.getName();
		if (!name.endsWith(".lisp"))
			throw new RuntimeException("Can only load files that end with .lisp");

		String label = name.substring(0, name.indexOf(".lisp"));
		return load(label, file);
	}
	
	/**
	 * Load in a list of instances from the given file.  Each instance
	 * is given the class label that is handed in.
	 * @param label
	 * @param file
	 * @return
	 */
	public static List<Instance> load(String label, File file) {
		return load(label, file, new HashMap<String,String>(), new HashSet<String>());
	}
	
	/**
	 * Load in a list of instances from the given file.  Each instance
	 * will be given the class label that is handed in.
	 * @param label
	 * @param file
	 * @param rewrite -- rewrite the propositions found in this map with
	 * the values stored with them.
	 * @param exclude -- ignore any intervals with the propositions
	 * found in the exclude set
	 * @return
	 */
	public static List<Instance> load(String label, File file, Map<String,String> rewrite, Set<String> excludeSet) { 
		List<Instance> instances = new ArrayList<Instance>();

		try { 
			FileReader fileReader = new FileReader(file);
			PushbackReader reader = new PushbackReader(fileReader);

			List<Object> episode = LispReader.read(reader);
			while (episode != null) {
				int id = (Integer) episode.get(0);
				List<Interval> intervalSet = new ArrayList<Interval>();

				List<Object> intervals = (List<Object>) episode.get(1);
				for (Object o : intervals) { 
					List<Object> list = (List<Object>) o;
					Interval interval = new Interval();
					interval.file = file.getName();
					interval.episode = id;
					interval.name = (String) list.get(0);
					if (rewrite.containsKey(interval.name)) 
						interval.name = rewrite.get(interval.name);

					interval.start = (Integer) list.get(1);
					interval.end = (Integer) list.get(2);

					boolean add = true;
					for (String exclude : excludeSet) { 
						if (interval.name.endsWith(exclude)) { 
							add = false;
							break;
						}
					}

					if (add)
						intervalSet.add(interval);
				}

				instances.add(new Instance(label, id, intervalSet));

				episode = LispReader.read(reader);
			}
		} catch (Exception e) { 
			e.printStackTrace();
		}
		return instances;
	}
}